/*
 * Copyright 2010 Biz-e (info@biz-e.nl)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.biz_e.acl.server.dao;

import java.util.ArrayList;
import java.util.List;

import nl.biz_e.acl.shared.model.Membership;
import nl.biz_e.acl.shared.model.User;
import nl.biz_e.acl.shared.model.UserGroup;
import nl.biz_e.appengine.lib.server.objectify.AbstractBaseDao;
import nl.biz_e.appengine.lib.server.objectify.ObjectifyUtils;

import com.googlecode.objectify.Key;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Query;

/**
 * DAO for accessing and manipulating {@link Membership} entities
 * 
 * @author Joost A. Bloemsma
 * 
 */
public class MembershipDao extends AbstractBaseDao<Membership> {
    static {
        ObjectifyService.register(Membership.class);
        ObjectifyService.register(User.class);
        ObjectifyService.register(UserGroup.class);
    }

    /**
     * Constructs a new MembershipDao instance
     */
    public MembershipDao() {
        super(Membership.class);
    }

    /**
     * Returns the {@link Key} of the {@link Membership} describing the relation
     * between the passed user and group.
     * 
     * @param user
     * @param group
     * @return {@link Key}
     */
    public Key<Membership> getKey(User user, UserGroup group) {
        Query<Membership> q = ofy().query(Membership.class)
                .filter("user", user).filter("group", group);
        return q.getKey();
    }

    /**
     * Returns the {@link Membership} describing the relation
     * between the passed user and group.
     * 
     * @param user
     * @param group
     * @return {@link Membership}
     */
    public Membership get(User user, UserGroup group) {
        Query<Membership> q = ofy().query(Membership.class)
                .filter("user", user).filter("group", group);
        return q.get();
    }

    /**
     * Persists a new {@link Membership} based on the passed user and group, but
     * only if that relation doesn't exist yet.
     * 
     * @param user
     * @param group
     * @return The (new) {@link Membership}
     */
    public Membership save(User user, UserGroup group) {
        if ((user == null) || (group == null))
            return null;
        Membership mb = this.get(user, group);
        if (mb != null)
            return mb;
        mb = new Membership();
        mb.setUser(ObjectifyUtils.generateKey(user));
        mb.setGroup(ObjectifyUtils.generateKey(group));
        this.save(mb);
        return mb;
    }

    /**
     * Delete the membership relation between the user and group
     * 
     * @param user
     * @param group
     */
    public void delete(User user, UserGroup group) {
        this.delete(this.getKey(user, group));
    }

    /**
     * Returns all members of the passed group
     * 
     * @param group
     * @return a list of {@link User} instances
     */
    public List<User> getMembers(UserGroup group) {
        Query<Membership> q = ofy().query(Membership.class).filter("group",
                group);
        List<Key<User>> userKeys = new ArrayList<Key<User>>();
        for (Membership membership : q) {
            userKeys.add(membership.getUser());
        }
        UserDao userDao = new UserDao();
        return new ArrayList<User>(userDao.get(userKeys).values());
    }

    /**
     * Returns all groups the passed user is a member of
     * 
     * @param user
     * @return a list of {@link UserGroup} instances
     */
    public List<UserGroup> getGroups(User user) {
        Query<Membership> q = ofy().query(Membership.class)
                .filter("user", user);
        List<Key<UserGroup>> groupKeys = new ArrayList<Key<UserGroup>>();
        for (Membership membership : q) {
            groupKeys.add(membership.getGroup());
        }
        UserGroupDao groupDao = new UserGroupDao();
        return new ArrayList<UserGroup>(groupDao.get(groupKeys).values());
    }

    /**
     * Returns a collection ({@link Iterable}) of membership keys for the passed
     * user
     * 
     * @param user
     * @return {@link Iterable} of type {@link Membership}
     */
    public Iterable<Key<Membership>> getMembershipKeys(User user) {
        return ofy().query(Membership.class).filter("user", user).fetchKeys();
    }

    /**
     * Returns a collection ({@link Iterable}) of membership keys for the passed
     * usergroup
     * 
     * @param group
     * @return {@link Iterable} of type {@link Membership}
     */
    public Iterable<Key<Membership>> getMembershipKeys(UserGroup group) {
        return ofy().query(Membership.class).filter("group", group).fetchKeys();
    }
}
